package main

import (
	"bytes"
	"fmt"
	"github.com/ngaut/log"
	"os"
	"os/signal"
	"reflect"
	"regexp"
	"strings"
	"syscall"
	"sort"
)

//代码来自Go语言编程（许式伟）

func T_basic_type_decl() {
	var v1 int
	var v2 string
	var v3 [10]int //array
	var v4 []int //slice
	var v5 struct {
		f int
	}
	var v6 *int
	var v7 map[string]int
	var v8 func(a int) int

	var (
		v9 int
		v10 string
	)

	var a1 int = 10
	var a2 = 10 //编译器自动推导类型
	a3 := 1 //更简洁

	const Pi float64 = 3.1415926
	const zero = 0.0
	const (
		size int64 = 1024
		eof = -1
	)
	const u,v float32 = 0, 3 //多重赋值

	fmt.Println(v1,v2,v3,v4,v5,v6,v7,v8,v9,v10,a1,a2,a3)
}


//code snippet 2-5 in book
func t_closure() {
	var j int = 5
	a := func()(func()) {
		var i int = 10
		return func() {
			fmt.Println("i,,j:",i,j)
		}
	}()

	a()
	j *=2
	a()
}


func t_pass_pointer_to_interface() {
	some := func(check *interface{}) {
		*check = "some"
	}
	var one interface{}

	some(&one)
	fmt.Println(one)

	some2 := func(c interface{}) {
		c = "some2"
	}
	some2(one)
	fmt.Println("after some2:", one) //some, unchanged

	// use reflect
	some3 := func(c interface{}) {
		val := reflect.ValueOf(c)
		//json.Unmarshal中就有这样的用法
		if val.Kind() != reflect.Ptr {
			panic("must be pointer")
		}
		val.Elem().Set(reflect.ValueOf("some3"))
	}
	some3(one)
	fmt.Println(one)
}


func t_use_channel_pass_signal()  {
	sigs := make(chan os.Signal, 1)
	done := make(chan bool, 1)

	signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)

	go func() {
		sig := <- sigs
		fmt.Println("recv sig:", sig)
		done <- true
	}()

	fmt.Println("waiting sig ")
	<- done
	fmt.Println("end")
}

func t_regex()  {
	//https://gobyexample.com/regular-expressions
	match0, _ := regexp.MatchString("p([a-z]+)ch", "peach")
	fmt.Println(match0)
	match0, _ = regexp.MatchString("p([a-z]?)ch", "peach") //false
	fmt.Println(match0)
	match0, _ = regexp.MatchString("p([a-z]?)ch", "pch") //true
	fmt.Println(match0)
	match0, _ = regexp.MatchString("p([a-z]?)ch", "pech") //true
	fmt.Println(match0)

	s := "peach punch"
	fmt.Println("creating a regexp object ...")
	r, _ := regexp.Compile("p([a-z]+)ch")
	fmt.Println(r.MatchString("peach"))
	fmt.Println(r.FindString(s)) //peach,它无法区分是匹配到了空，还是没匹配成
	fmt.Println(r.FindStringIndex(s)) // [0,5]
	fmt.Println(r.FindStringSubmatch(s)) // [peach ea]
	fmt.Println(r.FindStringSubmatchIndex(s)) //[0 5 1 3], 其中一个长度为5，一个长度为2

	fmt.Println(r.FindAllString("peach pun2ch pinch", -1))
	fmt.Println(r.FindAllStringSubmatchIndex("peach pun2ch pinch", -1)) // in匹配的是14 16号位置

	fmt.Println(r.FindAllString("peach punch pinch", 2)) // limit the number of matches

	fmt.Println(r.ReplaceAllString("a peach", "fruit")) // 替换操作，a fruit
	in := []byte("a peach")
	out := r.ReplaceAllFunc(in, bytes.ToUpper) //函数式风格
	fmt.Println(string(out))

	var containername = "10.1.a1:10056:1200768098"
	if len(strings.Split(containername, ":")) != 3 {
		fmt.Println(containername, " format error")
		return
	}
	match0, err := regexp.MatchString("(.*):([0-9]{1,5}):([0-9]+)", containername)
	if ! match0 {
		log.Error(err)
		return
	}

	var re = regexp.MustCompile(`(?m)^[0-9]{2}$`)
	var str = `123`
	var str2 = "123"
	fmt.Println(str == str2)

	for i, match := range re.FindAllString(str, -1) {
		fmt.Println(match, "found at index ", i)
	}
}

//https://stackoverflow.com/questions/45472816/golang-a-map-of-functions-with-a-receiver
type someStruct struct {
	x int
}
func (s someStruct) someFunc() int {
	println("s is", s.x) //参数之间自动加空格
	return s.x
}
func (s someStruct) deferFunc() {
	println("before defer")
	defer s.someFunc()
	println("after defer")

}
func (s someStruct) foo(b bool, i int) { fmt.Printf("foo: %v\n", b) }
func (s someStruct) bar(b int) { fmt.Println("bar: ", b) }
func (s someStruct) fooWith() error { fmt.Println("fooWith no parameter, but return error"); return nil }
func normalFunc(x int) int { return x }

type rpcCommand struct {
	name string
	handler func(someStruct)
	help string
}

var (
	table = map[string]rpcCommand {
		"foo": {
			"foo", func(s someStruct) {
				s.foo(true, 2)
			}, "foo help",
		},
	}
)

func t_map_of_functions()  {
	m0 := make(map[string]func(int)int)
	m0["k"] = normalFunc
	println("calling normalFunc:", m0["k"](2))

	m := make(map[string]func(someStruct)int)
	s := someStruct{2}
	m["a"] = someStruct.someFunc  // method expression
	println("calling method: ", m["a"](s))

	// defer test
	s.deferFunc()

	commandMap := map[string]rpcCommand {
		"foo": {
			"foo", func(s someStruct) {
				s.foo(true, 2)
			}, "foo help",
		},
		"bar": {
			"bar", func(s someStruct) {
				s.bar(1)
			}, "bar help",
		},
		"foowith": {
			"foowith", func(s someStruct) {
				s.fooWith()
			}, "foowith help",
		},
	}
	for name, cmd := range commandMap {
		fmt.Println("running ", name)
		cmd.handler(s)
	}

	fmt.Println("use global table:")
	table["foo"].handler(s)

}

//variadic function : https://medium.com/rungo/variadic-function-in-go-5d9b23f4c01a
//...int : pack operation, slice... : unpack operator
func getMultiples(factor int, args ...int) []int {
	multiples := make([]int, len(args))
	for i,val := range args {
		multiples[i] = val * factor
	}
	return multiples
}

type foo struct {
	a int
}

func t_pointer_passed_by_value() {
	modify1 := func(f, w *foo) {
		// 这两种赋值对外层map的影响不一样！！！
		f = w
		//f.a = w.a
		fmt.Printf("modify1: %v\n", f.a)
	}
	modify2 := func(f **foo, w *foo) {
		*f = w
		fmt.Printf("modify2: %v\n", *f)
	}
	t1 := func() {
		m := make(map[string]*foo)
		m["a"] = &foo { 1}
		w := &foo{2}
		// 指针按值传递，并不会修改实参 !!
		modify1(m["a"], w)
		fmt.Printf("m[a]: %v\n", m["a"])
	}

	t2 := func() {
		m := make(map[string]*foo)
		m["a"] = &foo { 1}
		w := &foo{2}
		f := m["a"]
		modify2(&f, w)
		// m["a"]并没有被修改
		fmt.Printf("m[a]: %v, f: %v\n", m["a"], f)
	}

	t1()
	fmt.Printf("in between\n")
	t2()
}

func sortSlice() {
	a := []int{5, 3, 4, 7, 8, 9}
	sort.Slice(a, func(i, j int) bool {
		return a[i] < a[j]
	})
	for _, v := range a {
		fmt.Println(v)
	}
}

func ab() (string, bool) {
	return "ab", true
}

func main() {
	if os.Getenv("HOME") != "" {
		fmt.Printf("HOME: %v\n", os.Getenv("HOME"))
	}

	var ok bool
	if info, ok := ab(); ok {
		ok = true
		fmt.Println(info)
	}
	fmt.Printf("%v\n", ok)

	
	//sortSlice()
	//t_pointer_passed_by_value()
	//t_map_of_functions()
	//t_closure()
	//t_pass_pointer_to_interface()
	//t_regex()
}